package com.smartian.dnshosts;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.os.Build;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * app 内DNS Hosts映射工具
 */
public class DnsHostsManager {
    private final DnsHookProxyImpl mDnsHookProxyImpl;
    public DnsHostsManager(DnsHostList dnsHostList) {
        this.mDnsHookProxyImpl = new DnsHookProxyImpl(dnsHostList);
    }
    public static List<String> getDnsServers(Context context) {
        List<String> dnsServerList = new ArrayList();
        if (Build.VERSION.SDK_INT >= 23) {
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            Network network = connectivityManager.getActiveNetwork();
            LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
            List<InetAddress> dnsServers = linkProperties.getDnsServers();
            for (InetAddress addr : dnsServers) {
                dnsServerList.add(addr.getHostAddress());
            }
        } else {
            final String re1 = "^\\d+(\\.\\d+){3}$";
            final String re2 = "^[0-9a-f]+(:[0-9a-f]*)+:[0-9a-f]+$";
            Class SystemProperties = null;
            try {
                SystemProperties = Class.forName("android.os.SystemProperties");
                Method method = SystemProperties.getMethod("get", new Class[]{String.class});
                final String[] netdns = new String[]{"net.dns1", "net.dns2", "net.dns3", "net.dns4"};
                for (int i = 0; i < netdns.length; i++) {
                    Object[] args = new Object[]{netdns[i]};
                    String v = (String) method.invoke(null, args);
                    if (v != null &&
                            (v.matches(re1) || v.matches(re2)) &&
                            !dnsServerList.contains(v))
                        dnsServerList.add(v);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return dnsServerList;
    }
    public static void registerDns(Map<String,String> dnsHostMap) {
        DnsHostList dnsHostList = new DnsHostList();
        dnsHostList.addDnsHosts(dnsHostMap);
        DnsInetAddress appInetAddress = new DnsInetAddress(new DnsHostsManager(dnsHostList));
        appInetAddress.hook();
    }
    protected boolean shouldHookProxy(Method method, Object[] args) {
        if (method == null) {
            return false;
        }
        if (!mDnsHookProxyImpl.canLookup()) {
            return false;
        }
        String methodName = method.getName();
        if (!mDnsHookProxyImpl.isHookMethod(methodName)) {
            return false;
        }
        return true;
    }
    public Object lookup(String name, Class<?>[] parameterTypes, Object[] args) {
        try {
            Method method = DnsHookProxyImpl.class.getDeclaredMethod(name, parameterTypes);
            method.setAccessible(true);
            return (InetAddress[]) method.invoke(mDnsHookProxyImpl, args);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
